#include "ecv_filter.h"


#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include <unistd.h>


G_DEFINE_TYPE (EcvFilter, ecv_filter, G_TYPE_OBJECT);

#define ECV_FILTER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ECV_TYPE_FILTER, EcvFilterPrivate))

struct _EcvFilterPrivate
{
  char * data;
  int datasz;
  int width;
  int height;
  int bpp;
};

enum
{
  PROP_0,

  PROP_ECV_WIDTH,
  PROP_ECV_HEIGHT,
  PROP_ECV_BPP
};

static void
ecv_filter_set_property (GObject      *object,
                        guint         property_id,
                        const GValue *value,
                        GParamSpec   *pspec)
{
  EcvFilter *self = ECV_FILTER (object);

  switch (property_id)
    {
    case PROP_ECV_WIDTH:
      self->priv->width = g_value_get_uint (value);
      break;

    case PROP_ECV_HEIGHT:
      self->priv->height = g_value_get_uint (value);
      break;

    case PROP_ECV_BPP:
      self->priv->bpp = g_value_get_uint (value);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
      break;
    }
}

static void
ecv_filter_get_property (GObject    *object,
                        guint       property_id,
                        GValue     *value,
                        GParamSpec *pspec)
{
  EcvFilter *self = ECV_FILTER (object);

  switch (property_id)
    {
    case PROP_ECV_WIDTH:
      g_value_set_uint (value, self->priv->width);
      break;

    case PROP_ECV_HEIGHT:
      g_value_set_uint (value, self->priv->height);
      break;

    case PROP_ECV_BPP:
      g_value_set_uint (value, self->priv->bpp);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
      break;
      }
}

static void
ecv_filter_dispose (GObject *gobject)
{
  EcvFilter *self = ECV_FILTER (gobject);

  /* 
   * In dispose, you are supposed to free all types referenced from this
   * object which might themselves hold a reference to self. Generally,
   * the most simple solution is to unref all members on which you own a 
   * reference.
   */

  /* dispose might be called multiple times, so we must guard against
   * calling g_object_unref() on an invalid GObject.
   */

  /*  if (self->priv->)
    {
      g_object_unref (self->priv->an_object);
      }*/

  /* Chain up to the parent class */
  G_OBJECT_CLASS (ecv_filter_parent_class)->dispose (gobject);
}

static void
ecv_filter_finalize (GObject *gobject)
{
  EcvFilter *self = ECV_FILTER (gobject);

  if (self->priv->data != NULL)
    {
      free(self->priv->data);
      self->priv->data = NULL;
    }

  //  g_free (self->a_string);

  /* Chain up to the parent class */
  G_OBJECT_CLASS (ecv_filter_parent_class)->finalize (gobject);
}

static GObject *
ecv_filter_constructor (GType                  gtype,
                       guint                  n_properties,
                       GObjectConstructParam *properties)
{
  GObject *obj;

  {
    /* Always chain up to the parent constructor */
    EcvFilterClass *klass;
    GObjectClass *parent_class;  
    parent_class = G_OBJECT_CLASS (ecv_filter_parent_class);
    obj = parent_class->constructor (gtype, n_properties, properties);
  }
  
  /* update the object state depending on constructor properties */

  return obj;
}

static void
ecv_filter_class_init (EcvFilterClass *klass)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);

  GParamSpec *pspec;

  gobject_class->dispose = ecv_filter_dispose;
  gobject_class->finalize = ecv_filter_finalize;
  gobject_class->set_property = ecv_filter_set_property;
  gobject_class->get_property = ecv_filter_get_property;

  pspec = g_param_spec_uint ("width",
			     "",
			     "filter width",
			     1,
			     65534,
			     320,
			     G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
  
  g_object_class_install_property (gobject_class,
                                   PROP_ECV_WIDTH,
                                   pspec);

  pspec = g_param_spec_uint ("height",
			     "",
			     "filter height",
			     1,
			     65534,
			     240,
			     G_PARAM_READWRITE);
  g_object_class_install_property (gobject_class,
                                   PROP_ECV_HEIGHT,
                                   pspec);

  pspec = g_param_spec_uint ("bpp",
			     "",
			     "filter bytes per pixel",
			     1,
			     65534,
			     24,
			     G_PARAM_READWRITE);
  g_object_class_install_property (gobject_class,
                                   PROP_ECV_BPP,
                                   pspec);
  
  g_type_class_add_private (klass, sizeof (EcvFilterPrivate));
  gobject_class->constructor = ecv_filter_constructor;
}

static void
ecv_filter_init (EcvFilter *self)
{
  self->priv = ECV_FILTER_GET_PRIVATE (self);

  //  self->priv->an_object = g_object_new (ECV_TYPE_BA, NULL);
}

//------------------------------------------------------
/*                     methods                        */

void
ecv_filter_process (EcvFilter *self)
{
  g_return_if_fail (ECV_IS_FILTER (self));
  ECV_FILTER_GET_CLASS (self)->process (self);
}

void
ecv_filter_create (EcvFilter *self)
{
  g_return_if_fail (ECV_IS_FILTER (self));
  ECV_FILTER_GET_CLASS (self)->create (self);
}

int
ecv_filter_set (EcvFilter *self, char * data, int size)
{
  g_return_if_fail (ECV_IS_FILTER (self));

  self->priv->data = data;
  self->priv->datasz = size;
  return 0;
}

char *
ecv_filter_get_data (EcvFilter *self)
{
  g_return_if_fail (ECV_IS_FILTER (self));
  return self->priv->data;
}

int
ecv_filter_get_data_size (EcvFilter *self)
{
  g_return_if_fail (ECV_IS_FILTER (self));
  
  return self->priv->datasz;
}
//------------------------------------------------------

EcvFilter * 
ecv_filter_new (int width, int height, int bpp)
{
  return g_object_new (ECV_TYPE_FILTER,
		       "width", width,
		       "height", height,
		       "bpp", bpp,
		       NULL);
}
